 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.update.standalone;

 import java.net.*;
 import java.util.ArrayList ;

 import org.eclipse.core.runtime.*;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.update.configuration.*;
 import org.eclipse.update.core.*;
 import org.eclipse.update.internal.core.*;
 import org.eclipse.update.internal.operations.*;
 import org.eclipse.update.operations.*;
 import org.eclipse.update.search.*;

 /**
  * Command to update and existing feature.
  * <p>
  * <b>Note:</b> This class/interface is part of an interim API that is still under development and expected to
  * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
  * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
  * (repeatedly) as the API evolves.
  * </p>
  * @since 3.0
  */
 public class UpdateCommand extends ScriptedCommand {

     private IConfiguredSite targetSite;
     private UpdateSearchRequest searchRequest;
     private UpdateSearchResultCollector collector;
     private String featureId;
     //private String version;
 private IFeature currentFeature;

     /**
      * Update command for updating a feature to a newer version.
      * @param featureId
      * @param verifyOnly
      * @throws Exception
      */
     public UpdateCommand(String featureId, String verifyOnly)
     throws Exception {
         this(featureId, null, verifyOnly);
     }
     
     /**
      * Update command for updating a feature to a specified newer version.
      * @param featureId
      * @param version
      * @param verifyOnly
      * @throws Exception
      */
     public UpdateCommand(String featureId, String version, String verifyOnly)
         throws Exception {

         super(verifyOnly);

         try {
             this.featureId = featureId;
             //this.version = version;
 if (featureId != null) {
                 this.targetSite =
                     UpdateUtils.getSiteWithFeature(
                         getConfiguration(),
                         featureId);
                 if (targetSite == null) {
                     throw new Exception (NLS.bind(Messages.Standalone_noConfigSiteForFeature, (new String [] { featureId })));
                 }
                 IFeature[] currentFeatures =
                     UpdateUtils.searchSite(featureId, targetSite, true);
                 if (currentFeatures == null || currentFeatures.length == 0) {
                     throw new Exception (NLS.bind(Messages.Standalone_noFeatures3, (new String [] { featureId })));
                 }
                 this.currentFeature = currentFeatures[0];
             } else {
                 // Get site to install to
 IConfiguredSite[] sites =
                     getConfiguration().getConfiguredSites();
                 for (int i = 0; i < sites.length; i++) {
                     if (sites[i].isProductSite()) {
                         targetSite = sites[i];
                         break;
                     }
                 }
             }
             if (currentFeature == null)
                 searchRequest = UpdateUtils.createNewUpdatesRequest(null);
             else {
                 searchRequest =
                     UpdateUtils.createNewUpdatesRequest(
                         new IFeature[] { currentFeature });
                 if (version != null)
                     searchRequest.addFilter(
                         new VersionedIdentifiersFilter(
                             new VersionedIdentifier[] { new VersionedIdentifier(featureId, version) }));
             }

             collector = new UpdateSearchResultCollector();

         } catch (MalformedURLException e) {
             StandaloneUpdateApplication.exceptionLogged();
             UpdateCore.log(e);
         } catch (CoreException e) {
             StandaloneUpdateApplication.exceptionLogged();
             UpdateCore.log(e);
         }
     }

     /**
      */
     public boolean run(IProgressMonitor monitor) {
         // check if the config file has been modifed while we were running
 IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
         if (status != null) {
             UpdateCore.log(status);
             return false;
         }
         try {
             monitor.beginTask(Messages.Standalone_updating, 4);
             searchRequest.performSearch(collector, new SubProgressMonitor(monitor,1));
             IInstallFeatureOperation[] operations = collector.getOperations();
             if (operations == null || operations.length == 0) {
                 StandaloneUpdateApplication.exceptionLogged();
                 UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.Standalone_noUpdate, (new String [] { featureId })), null));
                 return false;
             }

             // Check for duplication conflicts
 ArrayList conflicts =
                 DuplicateConflictsValidator.computeDuplicateConflicts(
                     operations,
                     getConfiguration());
             if (conflicts != null) {
                 StandaloneUpdateApplication.exceptionLogged();
                 UpdateCore.log(Utilities.newCoreException(Messages.Standalone_duplicate, null));
                 return false;
             }
             
             if (isVerifyOnly()) {
                 status = OperationsManager.getValidator().validatePendingChanges(operations);
                 if (status != null && status.getCode() == IStatus.ERROR)
                     throw new CoreException(status);
                 else
                     return true;
             }

             IBatchOperation installOperation =
                 OperationsManager
                     .getOperationFactory()
                     .createBatchInstallOperation(
                     operations);
             try {
                 installOperation.execute(new SubProgressMonitor(monitor,3), this);
                 System.out.println(
                         Messages.Standalone_feature
                         + featureId
                         + " " //$NON-NLS-1$
 + Messages.Standalone_updated);
                 return true;
             } catch (Exception e) {
                 StandaloneUpdateApplication.exceptionLogged();
                 UpdateCore.log(
                     Utilities.newCoreException(
                             NLS.bind(Messages.Standalone_noUpdate, (new String [] { featureId })),
                         e));
                 return false;
             }
         } catch (CoreException ce) {
             status = ce.getStatus();
             if (status != null
                 && status.getCode() == ISite.SITE_ACCESS_EXCEPTION) {
                 // Just show this but do not throw exception
 // because there may be results anyway.
 System.out.println(Messages.Standalone_connection);
             } else {
                 StandaloneUpdateApplication.exceptionLogged();
                 UpdateCore.log(ce);
             }
             return false;
         } catch (OperationCanceledException ce) {
             return true;
         } finally {
             monitor.done();
         }
     }


     class UpdateSearchResultCollector implements IUpdateSearchResultCollector {
         private ArrayList operations = new ArrayList ();

         public void accept(IFeature feature) {

             IInstallFeatureOperation op =
                 OperationsManager.getOperationFactory().createInstallOperation(
                     null,
                     feature,
                     null,
                     null,
                     null);

             IConfiguredSite site =
                 UpdateUtils.getDefaultTargetSite(getConfiguration(), op);
             if (site == null)
                 site = UpdateUtils.getAffinitySite(getConfiguration(), feature);
             if (site == null)
                 site = targetSite;

             op.setTargetSite(site);
             operations.add(op);
         }
         public IInstallFeatureOperation[] getOperations() {
             IInstallFeatureOperation[] opsArray =
                 new IInstallFeatureOperation[operations.size()];
             operations.toArray(opsArray);
             return opsArray;
         }
     }
 }

